﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Beacon.SPC
{

    /// <summary>
    /// 4 out of 5 consecutive points fall beyond the 1σ limit (in zone B or beyond), 
    /// on the same side of the centerline.
    /// </summary>
    public class WERule3 : ISpcRule
    {
        #region Members
        private const int PointCount = 5;
        private const int ViolateCount = 4;

        SpcControlSide _side = SpcControlSide.Both;
        SpcControlLimit _limit = null;

        SpcDataQueue _queue = new SpcDataQueue(PointCount);

        #endregion

        #region Constructor
        public WERule3(SpcControlSide side, SpcControlLimit limit)
        {
            _side = side;
            _limit = limit;
        }
        #endregion

        #region ISpcRule Members

        /// <summary>
        /// return rule type
        /// </summary>
        /// <returns></returns>
        public SpcRules RuleType()
        {
            return SpcRules.WERule3;
        }

        /// <summary>
        /// return rule point count
        /// </summary>
        /// <returns></returns>
        public int GetRulePointCount()
        {
            return PointCount;
        }

        /// <summary>
        /// add point
        /// </summary>
        /// <param name="data" type="double"></param>
        /// <returns> true if data is violated the rule, others false</returns>
        public bool AddPoint(double data)
        {
            _queue.Enqueue(data);
            bool rlt = violate();
            if (rlt)
                Reset();

            return rlt;
        }

        /// <summary>
        /// add point with sample size
        /// limits for data point will be calculated with sample size.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="sampleSize"></param>
        /// <returns>true if data is violated the rule, others false</returns>
        public bool AddPoint(double data, double sampleSize)
        {
            _limit.Calculate((int)sampleSize);
            return AddPoint(data);
        }

        public void Reset()
        {
            _queue.Clear();
        }

        #endregion

        #region Private Functions

        /// <summary>
        /// travel through the queue to check.
        /// </summary>
        /// <returns></returns>
        private bool violate()
        {
            int above = 0;
            int below = 0;
            foreach (double d in _queue)
            {
                if (d > _limit.UOL)
                    above++;

                if (d < _limit.LOL)
                    below++;
            }

            switch (_side)
            {
                case SpcControlSide.Upper:
                    if (above >= ViolateCount)
                        return true;
                    break;
                case SpcControlSide.Lower:
                    if (below >= ViolateCount)
                        return true;
                    break;
                case SpcControlSide.Both:
                    if (above >= ViolateCount || below >= ViolateCount)
                        return true;
                    break;
            }
            return false;
        }

        #endregion
    }
}
